package prefix.transaction;

import java.math.BigDecimal;
import java.util.Date;

import javax.persistence.LockModeType;

import models.OrderDetail;
import models.PayDetail;
import models.Transaction;
import models.Transaction.Type;
import prefix.exception.TransactionException;
import prefix.exception.TransactionException.CODE;
import prefix.integration.wm.AbstractWalletManager.ExecutionStatus;
import prefix.util.JPAUtil;
import prefix.util.OverallUtil;
import repository.OrderRepository;
import repository.PayRepository;

public class TransferFactory extends TransactionFactory {

    public TransferFactory() {
        // TODO Auto-generated constructor stub
    }

    abstract class TransferTransaction extends BasicTransaction {
        @Override
        Integer executeCreateTransaction() throws TransactionException {
            throw new TransactionException(CODE.NO_NEED_CREATION);
        }

        @Override
        ExecutionStatus executeRollbackTransaction() throws TransactionException {
            // TODO Auto-generated method stub
            throw new TransactionException(CODE.NO_NEED_FAIL);
        }

    }

    public class T2_LENDER_ISSUE_FUNDS_TO_BORROWER extends TransferTransaction {

        public T2_LENDER_ISSUE_FUNDS_TO_BORROWER() {
            // TODO Auto-generated constructor stub
        }

        public T2_LENDER_ISSUE_FUNDS_TO_BORROWER(Transaction trans) {
            this.dbTrans = trans;
        }

        @Override
        Type[] getAcceptedTypes() {
            return new Type[] { Type.T2_LENDER_ISSUE_FUNDS_TO_BORROWER };
        }

        @Override
        void validateAmount() throws TransactionException {
            BigDecimal balance = manager.getBalancePendingInvest(this.dbTrans.getFromAid());
            if (balance.doubleValue() - this.dbTrans.getAmount() < 0)
                throw new TransactionException(CODE.NOT_ENOUGH_MONEY);
        }

        @Override
        ExecutionStatus executeTransaction() throws TransactionException {
            // TODO Auto-generated method stub
            try {
                if (this.dbTrans.getLoanId() == null)
                    throw new TransactionException(CODE.NO_LOAN);
                return manager.transferPendingInvestFunds(this.dbTrans.getFromAid(), this.dbTrans.getToAid(),
                        new BigDecimal(dbTrans.getAmount()));
            } catch (Exception e) {
                throw new TransactionException(CODE.ERROR_IN_WM, e);
            }
        }

    }

    public class T8_BORROWER_MTHLY_PAY_TO_LENDER extends TransferTransaction {

        public T8_BORROWER_MTHLY_PAY_TO_LENDER() {
            // TODO Auto-generated constructor stub
        }

        public T8_BORROWER_MTHLY_PAY_TO_LENDER(Transaction trans) {
            this.dbTrans = trans;
        }

        @Override
        Type[] getAcceptedTypes() {
            return new Type[] { Type.T8_BORROWER_MTHLY_PAY_TO_LENDER };
        }

        @Override
        void validateAmount() throws TransactionException {
            BigDecimal balance = manager.getBalance(this.dbTrans.getFromAid());
            if (OverallUtil.round2Decimal(balance).doubleValue() - this.dbTrans.getAmount() < 0)
                throw new TransactionException(CODE.NOT_ENOUGH_MONEY);
        }

        @Override
        ExecutionStatus executeTransaction() throws TransactionException {
            // TODO Auto-generated method stub
            try {
                if (this.dbTrans.getLoanId() == null)
                    throw new TransactionException(CODE.NO_LOAN);
                return manager.transferFunds(this.dbTrans.getFromAid(), this.dbTrans.getToAid(),
                        new BigDecimal(dbTrans.getAmount()));
            } catch (Exception e) {
                throw new TransactionException(CODE.ERROR_IN_WM, e);
            }
        }

        @Override
        public void afterExecuteTransaction() throws TransactionException {
            PayDetail detail = PayRepository.getSingleByProperty(PayDetail.class, "transId", this.dbTrans.getId(),
                    LockModeType.PESSIMISTIC_WRITE);
            if (detail == null)
                throw new TransactionException(CODE.NO_PAYDETAIL_ATTACHED);
            OrderDetail orderDetail = OrderRepository.getSingleByProperties(OrderDetail.class, new String[] {
                    "orderId", "loanId" }, new Object[] { this.dbTrans.getOrderId(), this.dbTrans.getLoanId() });

            if (orderDetail == null)
                throw new TransactionException(CODE.NO_ORDERDETAIL);
            JPAUtil.em().refresh(orderDetail, LockModeType.PESSIMISTIC_WRITE);

            orderDetail.setReceivedInt(orderDetail.getReceivedInt() + detail.getInterest());
            orderDetail.setReceivedLateFee(orderDetail.getReceivedLateFee() + detail.getLateFee());
            orderDetail.setReceivedPrncp(orderDetail.getReceivedPrncp() + detail.getPrincipal());

            detail.setStatus(PayDetail.Status.COMPLETED);
            detail.setCompletionD(new Date());

        }
    }

}
